module key_filter (
    
    input   wire                clk,
    input   wire                rst_n,
    
    input   wire                key,
    
    output  reg                 key_wave
);

    parameter       T           =   20000;
    
    localparam      KEY_OFF     =   4'b0001;
    localparam      ON_SHAKE    =   4'b0010;
    localparam      KEY_ON      =   4'b0100;
    localparam      OFF_SHAKE   =   4'b1000;

    reg             [3:0]       c_state;
    reg             [3:0]       n_state;
    
    reg             [1:0]       key_buf;
    wire                        key_r;
    
    reg             [20:0]      cnt;
    
    always @ (posedge clk) key_buf <= {key_buf[0], key};
    assign key_r = key_buf[1];
    
    always @ (posedge clk, negedge rst_n) begin
        if (rst_n == 0)
            c_state <= KEY_OFF;
        else
            c_state <= n_state;
    end
    
    always @ * begin
        case (c_state)
            KEY_OFF         :   if (key_r)
                                    n_state = KEY_OFF;
                                else    
                                    n_state = ON_SHAKE;
                                    
            ON_SHAKE        :   if (key_r)
                                    n_state = KEY_OFF;
                                else
                                    if (cnt >= T - 1)
                                        n_state = KEY_ON;
                                    else
                                        n_state = ON_SHAKE;
                                     
            KEY_ON          :   if (key_r)
                                    n_state = OFF_SHAKE;
                                else
                                    n_state = KEY_ON;
                                
            OFF_SHAKE       :   if (key_r)
                                    if (cnt >= T - 1)
                                        n_state = KEY_OFF;
                                    else
                                        n_state = OFF_SHAKE;
                                else
                                    n_state = KEY_ON;
                                    
            default         :       n_state = KEY_OFF;
        endcase
    end
    
    always @ (posedge clk, negedge rst_n) begin
        if (rst_n == 0)
            cnt <= 0;
        else
            case (c_state)
                KEY_OFF     :   cnt <= 0;
                
                ON_SHAKE    :   if (key_r)
                                    cnt <= 0;
                                else
                                    if (cnt < T - 1)
                                       cnt <= cnt + 1'b1;
                                    else
                                        cnt <= 0;
                                        
                KEY_ON      :   cnt <= 0;
                
                OFF_SHAKE   :   if (key_r)
                                    if (cnt < T - 1)
                                        cnt <= cnt + 1'b1;
                                    else
                                        cnt <= 0;
                                else
                                    cnt <= 0;
                   
                default     :       cnt <= 0;
            endcase
    end
    
    always @ (posedge clk, negedge rst_n) begin
        if (rst_n == 0)
            key_wave <= 1;
        else
            if (c_state == KEY_ON || c_state == OFF_SHAKE)
                key_wave <= 0;
            else
                key_wave <= 1;   
    end
    
endmodule 